// grid.cpp

#include <stdio.h>
#include <math.h>
#include <windows.h>
#include <d3d9.h>
#include <d3dx9tex.h>
#include <Dxerr.h>  

#include "grid.h"


Grid::Grid(
   int                  maxWidthVerticesP,
   int                  maxHeightVerticesP,
   D3DXVECTOR3            *v0P,
   D3DXVECTOR3            *v1P,
   D3DXVECTOR3            *v2P,
   D3DXVECTOR3            *v3P
) {
   int i, j, k;

   maxWidthVertices = maxWidthVerticesP;
   maxHeightVertices = maxHeightVerticesP;
   widthVertices = maxWidthVertices;
   heightVertices = maxHeightVertices;

   numVertices = widthVertices * heightVertices;
   widthFaces = widthVertices - 1;
   heightFaces = heightVertices - 1;
   numFaces = widthFaces * heightFaces * 2; // 2 triangles in each grid cell
   v0 = *v0P;
   v1 = *v1P;
   v2 = *v2P;
   v3 = *v3P;
   dv = v2 - v0;
   dv.x /= float(widthVertices - 1);
   dv.y /= 1;
   dv.z /= float(heightVertices - 1);

   // set up the vertex and normal and texture data
   vertices = new GRIDVERTEX[numVertices];

   for (j = 0, k = 0; j < heightVertices; j++)
   {
      for (i = 0; i < widthVertices; i++, k++)
	  {
         GetGridPoint(&(vertices[k].p), float(v0.x + i * dv.x), float(v0.z + j * dv.z));
         GetGridNormal(&(vertices[k].n), &(vertices[k].p));
         vertices[k].color = D3DCOLOR_ARGB(0,255,255,255);

		 vertices[k].u = vertices[k].p.x;
		 vertices[k].v = vertices[k].p.y;
      }
   }

   // set up the index data
   indexData = new WORD[numFaces * 3];

   // note direct x uses a CW winding order
   // vertices 0, 1, 2, 3 in the following configuration
   // 2        3
   //  
   //   
   // 0        1
   for (j=0, k=0; j < heightFaces; j++) {
      for (i=0; i < widthFaces; i++) {
         indexData[k++] = j*widthVertices + i;         // vertex 0
         indexData[k++] = (j+1)*widthVertices + i+1;   // vertex 3
         indexData[k++] = j*widthVertices + i+1;       // vertex 1
                    
         indexData[k++] = j*widthVertices + i;         // vertex 0
         indexData[k++] = (j+1)*widthVertices + i;     // vertex 2
         indexData[k++] = (j+1)*widthVertices + i+1;   // vertex 3
      }
   }
}

void Grid::Update(
) {
    // not used
}

void Grid::GetGridPoint(
   D3DXVECTOR3   *pt,
   float    x,
   float    z
) {
   float dy = (v2.y - v0.y) / (v2.z - v0.z);
   float y0 = v0.y + z * dy;
   float xc = float(0.0);
   float zc = float(0.0);
   float r = float(sqrt((x-xc)*(x-xc) + (z-zc)*(z-zc)));
   pt->x = x;
   pt->y = float(y0 + 5*cos(r*2.0*2*PI/185.0) +10*sin(x*3.0*PI/150.0));
   pt->z = z;   
}

void Grid::GetGridPoint(
   D3DXVECTOR3   *pt,
   int         i,          // row (from bottom to top)
   int         j           // column (from left to right)
) {
   *pt = vertices[j * maxHeightVertices * i].p;   
}

// these get grid normal methods are not accurate right now
void Grid::GetGridNormal(
   
   D3DXVECTOR3   *n,
   D3DXVECTOR3   *pt
) {
    n->x = 0.0f;
    n->y = 1.0f;
    n->z = 0.0f;
}

void Grid::GetGridNormal(
   D3DXVECTOR3   *n,
   int i,
   int j
) {
    n->x = 0.0f;
    n->y = 1.0f;
    n->z = 0.0f;
}

void Grid::CreateDirectXMesh(
    LPDIRECT3DDEVICE9       pd3dDevice
) {
    HRESULT hr;
    VOID* pData;
    hr = D3DXCreateMeshFVF(numFaces, numVertices, D3DXMESH_DYNAMIC, D3DFVF_GRIDVERTEX, pd3dDevice, &mesh);
    if (FAILED(hr))
    {
      char buf[2048];
      sprintf(buf, "Error: %s error description: %s\n",DXGetErrorString(hr),DXGetErrorDescription(hr));
      OutputDebugString(buf);
    }
   
	hr = mesh->LockVertexBuffer(D3DLOCK_DISCARD, (void**)&pData);
    if (FAILED(hr))
    {
      char buf[2048];
      sprintf(buf, "Error: %s error description: %s\n",DXGetErrorString(hr),DXGetErrorDescription(hr));
      OutputDebugString(buf);
    }


	// copy the vertices into the buffer
    memcpy( pData, vertices, numVertices * sizeof(GRIDVERTEX) );

	// unlock the vertex buffer
    mesh->UnlockVertexBuffer();

    mesh->LockIndexBuffer(0, &pData);

    memcpy(pData, indexData, numFaces * 3 * sizeof(WORD));

    mesh->UnlockIndexBuffer();        
}


void Grid::DrawDirectXMesh(
    LPDIRECT3DDEVICE9       pd3dDevice
) {
    HRESULT hr;
    hr = mesh->DrawSubset(0);

    if (FAILED(hr))
    {
      char buf[2048];
      sprintf(buf, "Error: %s error description: %s\n",DXGetErrorString(hr),DXGetErrorDescription(hr));
      OutputDebugString(buf);
    }
}
